package com.oig.sys.auth.service.impl;

import cn.hutool.core.util.StrUtil;
import com.oig.common.constants.CommonEnum;
import com.oig.common.exception.BadRequestException;
import com.oig.common.module.SysRequest;
import com.oig.sys.auth.dao.ITbDepartmentDao;
import com.oig.sys.auth.dto.DepartmentDto;
import com.oig.sys.auth.entity.TbDepartment;
import com.oig.sys.auth.service.ITbDepartUserService;
import com.oig.sys.auth.service.ITbDepartmentService;
import com.oig.sys.auth.vo.DepartmentVo;
import com.oig.sys.security.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * @author wuxl
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class TbDepartmentServiceImpl implements ITbDepartmentService {

	private final ITbDepartmentDao tbDepartmentDao;
	private final ITbDepartUserService departUserService;


	@Transactional
	@Override
	public DepartmentVo addDepartment(DepartmentDto departmentDto) {
		TbDepartment department = new TbDepartment();
		BeanUtils.copyProperties(departmentDto, department, "id");
		this.checkRole(department);
		if (departmentDto.getParentId()==null){
			department.setParentId(0);
			department.setParentName("无");
		}
		department.setStatus(CommonEnum.CommonStatusEnum.OK.getCode());
        department.setCreateTime(new Date());
        department.setCreateUserId(SecurityUtil.getDefineUserMain().getId());
        department.setCreateUserName(SecurityUtil.getDefineUserMain().getRealName());
        department.setLastUpdateName(department.getCreateUserName());
        department.setLastUpdateId(department.getCreateUserId());
        department.setLastUpdateTime(department.getCreateTime());
		this.tbDepartmentDao.save(department);
		DepartmentVo departmentVo = new DepartmentVo();
		BeanUtils.copyProperties(department,departmentVo);
		if (departmentDto.getUserList()!=null && !departmentDto.getUserList().isEmpty()){
			departmentVo.setUserList(departUserService.addDepartUser(department.getId(),departmentDto.getUserList()));
		}
		return departmentVo;
	}


	@Transactional
	@Override
	public void delDepartment(Integer departmentId) {
		TbDepartment department = this.tbDepartmentDao.getTbDepartmentById(departmentId) ;
		this.checkRole(department);
		if (!CommonEnum.CommonStatusEnum.DEL.getCode().equals(department.getStatus())){
			throw new BadRequestException("只有注销状态才能清除") ;
		}
		this.departUserService.delDepartUser(departmentId,null);
		this.tbDepartmentDao.delete(department);
	}

	private void checkRole(TbDepartment department){
		log.debug("entity={}",department);
		if (department==null){
			throw new BadRequestException("部门id错误") ;
		}
		if (SecurityUtil.getDefineUserMain().getTenantId()!=0){
			if (!department.getTenantId().equals(SecurityUtil.getDefineUserMain().getTenantId())){
				throw new BadRequestException("无租户权限");
			}
		}
	}

	@Transactional
	@Override
	public void cancelDepartment(Integer departmentId) {
		TbDepartment department = this.tbDepartmentDao.getTbDepartmentById(departmentId) ;
		this.checkRole(department);
		department.setStatus(CommonEnum.CommonStatusEnum.DEL.getCode());
		this.tbDepartmentDao.save(department);
	}

	@Transactional
	@Override
	public void revertDepartment(Integer departmentId) {
		TbDepartment department = this.tbDepartmentDao.getTbDepartmentById(departmentId) ;
		this.checkRole(department);
		if (!CommonEnum.CommonStatusEnum.DEL.getCode().equals(department.getStatus())){
			throw new BadRequestException("部门非注销状态") ;
		}
		department.setStatus(CommonEnum.CommonStatusEnum.OK.getCode());
		this.tbDepartmentDao.save(department);
	}

	@Transactional
	@Override
	public DepartmentVo updateDepartment(DepartmentDto departmentDto) {
		TbDepartment department = this.tbDepartmentDao.getTbDepartmentById(departmentDto.getId()) ;
		log.debug("department entity={}", department);
		this.checkRole(department);
		BeanUtils.copyProperties(departmentDto, department, "id","tenantId","tenantName");	//"parentId","parentName"
        department.setLastUpdateTime(new Date());
        department.setLastUpdateName(SecurityUtil.getDefineUserMain().getRealName());
        department.setLastUpdateId(SecurityUtil.getDefineUserMain().getId());
		this.tbDepartmentDao.save(department) ;
		DepartmentVo departmentVo = new DepartmentVo();
		BeanUtils.copyProperties(department,departmentVo);
		if (departmentDto.getUserList()!=null && !departmentDto.getUserList().isEmpty()){
			departmentVo.setUserList(this.departUserService.updateDepartUser(department.getId(), departmentDto.getUserList()));
		}
		return departmentVo;
	}

	@Transactional
	@Override
	public DepartmentVo addOrUpdateDepartment(DepartmentDto departmentDto) {
		if (StringUtils.isNotBlank(departmentDto.getDepartCode())){
			TbDepartment department = this.tbDepartmentDao.getByDepartCode(departmentDto.getDepartCode());
			if (department!=null){
				departmentDto.setId(department.getId());
			}
		}
		if (departmentDto.getId()!=null){
			log.debug("sync fs update department:{}",departmentDto);
			return this.updateDepartment(departmentDto);
		} else {
			log.debug("sync fs add department:{}",departmentDto);
			return this.addDepartment(departmentDto);
		}
	}

	@Override
	public List<DepartmentVo> findDepartTree(Integer tenantId) {
		List<DepartmentVo> departmentVoList = this.tbDepartmentDao.findByTenantId(tenantId);
		if (departmentVoList!=null){
			return this.buildOwnTree(0, departmentVoList);
		}
		return null;
	}


	private List<DepartmentVo> buildOwnTree(Integer parentId, List<DepartmentVo> departmentVoList){
		List<DepartmentVo> childList = new ArrayList<>();
		for(Iterator<DepartmentVo> iter = departmentVoList.iterator(); iter.hasNext();){	//用iterator可以移除元素
			DepartmentVo departmentVo = iter.next();
			if(parentId.equals(departmentVo.getParentId())){		//找到儿子节点
				iter.remove(); 		//从departmentVoList移除掉
				childList.add(departmentVo);//儿子列表
			}
		}
		//循环完之后，再循环刚刚的儿子列表，找出他们各自的儿子列表,这样应该递归不会太深
		for(DepartmentVo node  : childList){
			node.setChildren(this.buildOwnTree(node.getId(), departmentVoList));
		}
		log.debug(" departmentVoList size ={}", departmentVoList.size());
		return childList;
	}


	/**
	 * 使用jpa JpaSpecificationExecutor 动态查询
	 */
	@Override
	public List<DepartmentVo> listDepartment(SysRequest<DepartmentDto> departRequest) {
		Pageable pageable = departRequest.pageable() ;
		if (pageable.getSort().isUnsorted()){
			pageable.getSort().and(Sort.by(Sort.Direction.DESC, "createTime"));
		}
		Specification<TbDepartment> specification = new Specification<TbDepartment>(){
			@Override
			@Nullable
			public Predicate toPredicate(@NonNull Root<TbDepartment> root,@NonNull CriteriaQuery<?> criteriaQuery,@NonNull CriteriaBuilder criteriaBuilder) {
				List<Predicate> predicateList = new ArrayList<>();
				if (StrUtil.isNotBlank(departRequest.getParamDto().getDepartCode())){
					Path<String> departCodePath = root.get("departCode");
					predicateList.add(criteriaBuilder.equal(departCodePath, departRequest.getParamDto().getDepartCode()));
				}
				if (StrUtil.isNotBlank(departRequest.getParamDto().getDepartName())){
					Path<String> departNamePath = root.get("departName");
					predicateList.add(criteriaBuilder.like(departNamePath, "%"+departRequest.getParamDto().getDepartName()+"%"));
				}
				Path<String> statusPath = root.get("status");
				predicateList.add(criteriaBuilder.equal(statusPath, CommonEnum.CommonStatusEnum.OK.getCode()));
				Path<Integer> tenantIdPath = root.get("tenantId");
				predicateList.add(criteriaBuilder.equal(tenantIdPath, departRequest.getParamDto().getTenantId()));
				criteriaQuery.where(predicateList.toArray(new Predicate[0]));
				return criteriaQuery.getRestriction();
			}
		};
		Page<TbDepartment> page  = this.tbDepartmentDao.findAll(specification, pageable);

		List<DepartmentVo> departmentVoList = new ArrayList<>();
		//page.get().forEach();
		for (TbDepartment department : page.getContent()){
			DepartmentVo departmentVo = new DepartmentVo();
			BeanUtils.copyProperties(department,departmentVo);
			departmentVoList.add(departmentVo);
		}
		return departmentVoList;
	}


    @Override
    public DepartmentVo getDepartment(Integer departmentId) {
        DepartmentVo departmentVo = this.tbDepartmentDao.getVoById(departmentId) ;
		if (departmentVo==null){
			throw new BadRequestException("记录不存在") ;
		}
        departmentVo.setUserList(this.departUserService.getDepartUser(departmentId));
        return departmentVo;
    }

	@Transactional
	@Override
	public void delDepartmentNotInIdList(List<Integer> idList, Integer tenantId) {
		List<TbDepartment> departmentList = this.tbDepartmentDao.findTenantNeedCancelDepartment(idList, tenantId);
		if (departmentList!=null && !departmentList.isEmpty()){
			for (TbDepartment department:departmentList){
				log.debug("cancel department:{}", department);
				department.setStatus(CommonEnum.CommonStatusEnum.DEL.getCode());
				this.tbDepartmentDao.save(department);
			}
		}
	}
}
